﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace LiteExpress.Utilities.Hash
{
    //一致性hash实现，调用方法如下：
    //List<string> lstNode = new List<string>();
    //lstNode.AddRange(new string[] { "192.168.0.1", "192.168.0.2", "192.168.0.3", "192.168.0.4", "192.168.0.5" });
    //ConsistentHash consisHash = new ConsistentHash(lstNode, 160);
    //for (int i = 0; i < 1000; i++)
    //{
    //    string word = Guid.NewGuid().ToString();
    //    Console.WriteLine(i + "\t" + word + ":" + consisHash.getHostBykey(word));
    //}

    /// <summary>
    /// hash算法
    /// </summary>
    public class HashAlgorithm
    {
        //采用MD5 hash算法先构建16个字节的key
        public static byte[] getConsistentKeybyMd5(string host)
        {
            using (var md5 = new MD5CryptoServiceProvider())
            {
                return md5.ComputeHash(Encoding.UTF8.GetBytes(host));
            }
        }

        //4个字节一组=32位
        public static long getHashCode(byte[] arrConsistentKey, int rowpos)
        {
            if (arrConsistentKey == null)
            {
                return 0;
            }
            if (arrConsistentKey.Length != 16)
            {
                return 0;
            }
            if (rowpos < 0 || rowpos > 4)
            {
                return 0;
            }
            long result = ((long)(arrConsistentKey[3 + rowpos * 4] & 0xff) << 24)
                | ((long)(arrConsistentKey[2 + rowpos * 4] & 0xff) << 16)
                | ((long)(arrConsistentKey[1 + rowpos * 4] & 0xff) << 8)
                | ((long)(arrConsistentKey[0 + rowpos * 4] & 0xff) << 0);

            //32位的环
            return result & 0xffffffff;
        }
    }

    /// <summary>
    /// 一致性hash算法（包含虚拟节点）
    /// </summary>
    public class ConsistentHash
    {
        /// <summary>
        /// 节点，key映射
        /// </summary>
        private SortedList<long, string> nodeMap = new SortedList<long, string>();

        /// <summary>
        /// 虚拟节点重复个数
        /// </summary>
        private int VirtualNodeCount;

        /// <summary>
        /// 节点列表
        /// </summary>
        private List<string> NodeList;

        public ConsistentHash(List<string> nodelist, int virtualNodeCount)
        {
            VirtualNodeCount = virtualNodeCount;
            NodeList = nodelist;
            init();
        }

        private void init()
        {
            foreach (var node in NodeList)
            {
                //分四组，md5产生16个字节的key，可构建4个int类型的hashcode
                //16*8=4*4*8
                int runCount = VirtualNodeCount / 4;
                for (int i = 0; i < runCount; i++)
                {
                    //16个字节的数据key
                    byte[] hashkey = HashAlgorithm.getConsistentKeybyMd5(node + i);
                    for (int j = 0; j < 4; j++)
                    {
                        nodeMap.Add(HashAlgorithm.getHashCode(hashkey, j), node);
                    }
                }
            }
        }

        /// <summary>
        /// 根据关键字取得host服务器
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public String getHostBykey(string key)
        {
            long consistentkey = HashAlgorithm.getHashCode(HashAlgorithm.getConsistentKeybyMd5(key), 0);
            if (nodeMap.Keys.Contains(consistentkey))
            {
                return nodeMap[consistentkey];
            }
            var result = nodeMap.FirstOrDefault(p => p.Key > consistentkey);
            if (result.Key > 0)
            {
                return result.Value;
            }
            return nodeMap.FirstOrDefault().Value;
        }

    }
}